﻿using System;
using System.Collections.Generic;
using System.Windows;
using Duellum.Core;
using JpLabs.Extensions;

namespace Duellum.Wpf2d.Plugin
{
    public interface IMapRenderer
    {
		MapVisualHost VisualHost { get; set; }
		Size? GetMeasure(); //TODO: switch GetMeasure for GetRect
		void OnRender();
		
		IEnumerable<OverlayVisual> Visuals { get; }
		event Action<IMapRenderer,OverlayVisual> VisualAdded;
		event Action<IMapRenderer,OverlayVisual> VisualRemoved;
    }

	public static class MapZOrder
	{
		public const int BottomMost = 0;
		public const int Bottom = 4;
		public const int Medium = 16;
		public const int Top = 256;
		public const int TopMost = int.MaxValue;
	}

    public abstract class BaseMapRenderer : IMapRenderer
    {
		MapVisualHost visualHost;
		
		public MapVisualHost VisualHost
		{
			get { return visualHost; }
			set {
				if (visualHost != null) OnDetachVisualParent(visualHost);
				visualHost = value;
				if (visualHost != null) OnAttachVisualParent(visualHost);
			}
		}
		
		public abstract IEnumerable<OverlayVisual> Visuals { get; }

	    protected virtual OverlayVisual CreateVisual(int zOrder)
	    {
	        return new OverlayVisual(){ ZOrder = zOrder };
	    }
		
		protected virtual void OnAttachVisualParent(UIElement visualParent) {}
		protected virtual void OnDetachVisualParent(UIElement visualParent) {}
		
		public virtual Size? GetMeasure() { return null; }
		public abstract void OnRender();

		//TODO: convert these events to the EventHandler standard
		public event Action<IMapRenderer,OverlayVisual> VisualAdded;
		public event Action<IMapRenderer,OverlayVisual> VisualRemoved;
		
		protected virtual void OnAddVisual(OverlayVisual visual)
		{
			var ev = VisualAdded; if (ev != null) ev(this, visual);
		}

		protected virtual void OnRemoveVisual(OverlayVisual visual)
		{
			var ev = VisualRemoved; if (ev != null) ev(this, visual);
		}
	}

	public abstract class BaseMapSingleRenderer : BaseMapRenderer
	{
		OverlayVisual singleVisual;
		
		protected abstract int VisualZOrder { get; }
		
	    public OverlayVisual Visual
	    {
	        get {
	            //if (Visuals.IsEmpty()) base.AddVisual(CreateVisual());
	            //return Visuals.Single();
	            if (singleVisual == null) {
					singleVisual = CreateVisual(VisualZOrder);
					OnAddVisual(singleVisual);
				}
				return singleVisual;
	        }
	    }

		public override IEnumerable<OverlayVisual> Visuals
		{
			get { return Visual.ToEnumerable(); }
		}
	}

    public abstract class BaseMapMultipleRenderer : BaseMapRenderer
    {
		IList<OverlayVisual> visuals;
		
		public BaseMapMultipleRenderer()
		{
			visuals = new List<OverlayVisual>();
		}
		
		//REMARK: The only advantage of using several visuals is that they can have different ZOrder values
		public override IEnumerable<OverlayVisual> Visuals { get { return visuals; } }
		
		protected virtual void AddVisual(OverlayVisual visual)
		{
			visuals.Add(visual);
			base.OnAddVisual(visual);
		}

		protected virtual void RemoveVisual(OverlayVisual visual)
		{
			visuals.Remove(visual);
			base.OnRemoveVisual(visual);
		}
	}
}
